package org.lyricedit.domain.arpabet;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;


import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.lyricedit.domain.LexicalStress;
import org.lyricedit.domain.Phoneme;
import org.lyricedit.domain.PhonemeInstance;
import org.lyricedit.domain.hibernate.Word;

public class ArpabetDataAccess {

	Map<String, List<PhonemeInstance>> wordMap = new TreeMap<String, List<PhonemeInstance>>();
	Map<Phoneme,List<String>> lastVowelMap = new TreeMap<Phoneme, List<String>>();
	
	public ArpabetDataAccess(String string) throws IOException {
		wordMap = this.loadWordMap(string);
	}

	public List<PhonemeInstance> gePhonemesForWord(String word){
		return wordMap.get(word.toUpperCase());
	}
	
	public Map<String, List<PhonemeInstance>> loadWordMap(String filename) throws IOException{
		BufferedReader reader = new BufferedReader(new FileReader(filename));
		
		String line = null;
		
		Map<String, List<PhonemeInstance>> wordMap = new TreeMap<String, List<PhonemeInstance>>();
		
		while ((line = reader.readLine()) != null){
			if (Character.isLetter(line.charAt(0))){
				String[] wordPh = line.split("\\s+", 2);
				
				String word = wordPh[0];
				
				String [] phonemeStrings = wordPh[1].split("\\s+");
				
				ArrayList<PhonemeInstance> phonemeInstances = new ArrayList<PhonemeInstance>();
				
				for (String phoString : phonemeStrings){
					int stress = 0;
					if (Character.isDigit(phoString.charAt(phoString.length()-1))){
						stress = Integer.parseInt(phoString.substring(phoString.length()-1));
						phoString = phoString.substring(0, phoString.length()-1);
					}
					
					phonemeInstances.add(
							new PhonemeInstance(Phoneme.fromArpabet(phoString), LexicalStress.fromOrdinal(stress)));
				}
				
				wordMap.put(word, phonemeInstances);
				
				String string = word + " ";
				
				for (PhonemeInstance instance : phonemeInstances)
					string+=instance.getPhoneme();
				
				int lastVowel = getLastVowel(phonemeInstances);
				
				
				if (lastVowel >= 0){
					
					Phoneme phoneme = phonemeInstances.get(lastVowel).getPhoneme();
					if (!lastVowelMap.containsKey(phoneme))
							lastVowelMap.put(phoneme, new ArrayList<String>());
							
					lastVowelMap.get(phoneme).add(word);
				}
				
			}//if
			
		}//for
		
		return wordMap;
	}

	private int getLastVowel(List<PhonemeInstance> phonemeInstances) {
		
		for (int i = phonemeInstances.size()-1;i >= 0; i--){
			Phoneme p = phonemeInstances.get(i).getPhoneme();
			
			if (p.isVowel())
				return i;
		}
		
		return -1;
	}
	
	List<String> getRhymes(String word){
		List<PhonemeInstance> phonemeInstances = this.gePhonemesForWord(word);
		int lastVowelIndex = this.getLastVowel(phonemeInstances);
		Phoneme lastVowel = phonemeInstances.get(lastVowelIndex).getPhoneme();
		
		List<String> list = lastVowelMap.get(lastVowel);
		List<String> finalList = new ArrayList<String>();
		
		for (String s : list){
			List<PhonemeInstance> phonemes = this.gePhonemesForWord(s);
			
			int lastVowelIndexCandidate = this.getLastVowel(phonemes);
			
			if ((phonemes.size()-lastVowelIndexCandidate) != (phonemeInstances.size()-lastVowelIndex))
				continue;
			int i = lastVowelIndexCandidate;
			int j = lastVowelIndex;
			
			boolean match = true;
			for (;i<phonemes.size();i++,j++){
				if (phonemes.get(i).getPhoneme() != phonemeInstances.get(j).getPhoneme())
					match = false;
			}
			
			if (!match)
				continue;
			
			finalList.add(s.toLowerCase());
				
			
		}
		
		return finalList;
		
	}
	
	String getMeter(String word){
		List<PhonemeInstance> phonemeInstances = this.gePhonemesForWord(word);
		String result = "";
		for (PhonemeInstance instance: phonemeInstances)
			if (instance.getPhoneme().isVowel()){
				if (instance.getLexicalStress() == LexicalStress.NONE)
					result+=" -";
				else if (instance.getLexicalStress() == LexicalStress.PRIMARY)
					result+=" /";
				else 
					result+=" \\";
			}
		
		return result;
	}
	
	public static void main(String[] args) throws IOException {
		ArpabetDataAccess access = new ArpabetDataAccess("cmndict/cmudict.0.7a");
		
		BufferedReader r = new BufferedReader(new InputStreamReader(System.in));
		/*while (true)
		{
			
			List<String> words = access.getRhymes(r.readLine());
			
			for (String s: words){
				System.out.println(access.getMeter(s));
				System.out.println(s);
			}
		}*/
		
		SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
	    Session session = sessionFactory.openSession();
	    for (String wordName: access.wordMap.keySet()){
	    	Word word = new Word();
	    	word.setName(wordName);
	    	session.save(word);
	    	session.flush();
	    	session.evict(word);
	    }
	}
}
